package com.jyh.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 反射工具类
 * 
 * @author xusonghui
 *
 */
public class ReflectUtils {
//	public static void main(String[] args) throws Exception {
////		invokeStaticMethod("com.xsh.utils.bean.ReflectUtils", "aaa", Integer.parseInt("1"));
////		System.out.println("aaa=" + PaymentConstant.API_VERSION);
////		setFinalStatic(PaymentConstant.class.getField("API_VERSION"), "asdfasdfasdf");
////		System.out.println("aaa=" + PaymentConstant.API_VERSION);
//		System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName());
//	}
	/**
	 * 修改final static字段值
	 * @param field
	 * @param newValue
	 * @throws Exception
	 */
	public static void setFinalStatic(Field field, Object newValue) throws Exception {
		field.setAccessible(true);
		Field modifiersField = Field.class.getDeclaredField("modifiers");
		modifiersField.setAccessible(true);
		modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
		field.set(null, newValue);
	}

	/**
	 * 判断某个类的某个方法是否存在
	 * 
	 * @param className
	 * @param methodName
	 * @return
	 */
	public static Method checkClassMethod(String className, String methodName, Object... params) {
		try {
			Class<?> cls = Class.forName(className);
			if (cls == null) {
				throw new RuntimeException("没有发现" + className + "." + methodName);
			}
			if (params == null || params.length <= 0) {
				return cls.getDeclaredMethod(methodName);
			} else {
				Method methods[] = cls.getDeclaredMethods();
				Class<?> paramClass[] = getCls(params);
				for (Method method : methods) {
					Class<?> clas[] = method.getParameterTypes();
					if (method.getName().equals(methodName)
							&& equalList(Arrays.asList(paramClass), Arrays.asList(clas))) {
						return method;
					}
				}
			}
			throw new RuntimeException("没有发现" + className + "." + methodName);
		} catch (Exception e) {
			throw new RuntimeException("没有发现" + className + "." + methodName);
		}
	}

	private static boolean equalList(List<Class<?>> list1, List<Class<?>> list2) {
		if (list1.size() != list2.size())
			return false;
		list1 = refreshList(list1);
		list2 = refreshList(list2);
		for (Object object : list1) {
			if (!list2.contains(object))
				return false;
		}
		return true;
	}

	/**
	 * 修改list对应关系
	 * 
	 * @param list
	 * @return
	 */
	private static List<Class<?>> refreshList(List<Class<?>> list) {
		List<Class<?>> clas = new ArrayList<Class<?>>();
		for (Class<?> cla : list) {
			if (cla == Integer.class) {
				cla = Integer.TYPE;
			}
			if (cla == Double.class) {
				cla = Double.TYPE;
			}
			if (cla == Byte.class) {
				cla = Byte.TYPE;
			}
			if (cla == Float.class) {
				cla = Float.TYPE;
			}
			if (cla == Short.class) {
				cla = Short.TYPE;
			}
			if (cla == Long.class) {
				cla = Long.TYPE;
			}
			if (cla == Boolean.class) {
				cla = Boolean.TYPE;
			}
			clas.add(cla);
		}
		return clas;
	}

	/**
	 * 获取参数数组
	 * 
	 * @param params
	 * @return
	 */
	private static Class<?>[] getCls(Object... params) {
		Class<?>[] clss = new Class<?>[params.length];
		for (int i = 0; i < params.length; i++) {
			clss[i] = getClass(params[i]);
		}
		return clss;
	}

	/**
	 * 获取参数的class类型
	 * 
	 * @param param
	 * @return
	 */
	private static Class<?> getClass(Object param) {
		if (param == null) {
			return null;
		}
		Class<?> clsParams;
		if (param instanceof Map) {
			clsParams = Map.class;
		} else if (param instanceof List) {
			clsParams = List.class;
		} else {
			clsParams = param.getClass();
		}
		return clsParams;
	}

	/**
	 * 通过反射获取一个class
	 * 
	 * @param className
	 * @return
	 */
	public static Class<?> getClassByClassName(String className) {
		try {
			return Class.forName(className);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 反射调用方法
	 * 
	 * @param obj
	 * @param methodName
	 * @param params
	 * @return
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 */
	public static Object invokeMethod(String className, String methodName, Object... params)
			throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
			InvocationTargetException, ClassNotFoundException, InstantiationException {
		Class<?> obj = getClassByClassName(className);
		Object object = Class.forName(className).newInstance();
		Method method = checkClassMethod(obj.getName(), methodName, params);
		if (params == null) {
			method = obj.getClass().getMethod(methodName);
			return method.invoke(obj);
		}
		return method.invoke(object, params);
	}

	/**
	 * 反射调用方法
	 * 
	 * @param obj
	 * @param methodName
	 * @param params
	 * @return
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 */
	public static Object invokeStaticMethod(String className, String methodName, Object... params)
			throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
			InvocationTargetException, ClassNotFoundException, InstantiationException {
		Class<?> obj = getClassByClassName(className);
		Object object = Class.forName(className).newInstance();
		Method method = checkClassMethod(obj.getName(), methodName, params);
		if (params == null) {
			method = obj.getClass().getMethod(methodName);
			return method.invoke(obj);
		}
		return method.invoke(object, params);
	}

	/**
	 * 反射调用方法
	 * 
	 * @param obj
	 * @param methodName
	 * @param params
	 * @return
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	public static Object invokeMethod(Object obj, String methodName, Object... params) throws NoSuchMethodException,
			SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Method method = checkClassMethod(obj.getClass().getName(), methodName, params);
		if (params == null) {
			method = obj.getClass().getMethod(methodName);
			return method.invoke(obj);
		}
		return method.invoke(obj, params);
	}

	/**
	 * 反射调用静态方法方法
	 * 
	 * @param obj
	 * @param methodName
	 * @param params
	 * @return
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	public static Object invokeStaticMethod(Class<?> clsObj, String methodName, Object... params)
			throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
			InvocationTargetException {
		Method method = checkClassMethod(clsObj.getName(), methodName, params);
		return method.invoke(null, params);
	}
}
